﻿
using System;
using NUnit.Framework;

namespace HappyTemplate.Tests
{
	[TestFixture]
	public class LexerTests : TestFixtureHelper
	{
		[Test]
		public void LexSimpleVerbatim()
		{
			const string VERBATIM = "   verbatim   ";
			TemplateLexer lexer = NewLexer(VERBATIM);

			NextTokenAssert(lexer, TokenType.Verbatim, VERBATIM);

			NextTokenAssert(lexer, TokenType.EndTemplate, "}>");
			Assert.IsTrue(lexer.Eof);
			AssertNoErrors();
		}

		[Test]
		public void	LexIdentifierWithoutWhitespace()
		{
			TemplateLexer lexer = NewLexer("<$test$>");

			NextTokenAssert(lexer, TokenType.Identifier, "test");

			NextTokenAssert(lexer, TokenType.EndTemplate, "}>");
			Assert.IsTrue(lexer.Eof);

			AssertNoErrors();
		}


		[Test]
		public void LexIdentifierWithWhitespace()
		{
			TemplateLexer lexer = NewLexer("<$    test   $>");

			NextTokenAssert(lexer, TokenType.Identifier, "test");

			NextTokenAssert(lexer, TokenType.EndTemplate, "}>");
			Assert.IsTrue(lexer.Eof);

			AssertNoErrors();
		}

		[Test]
		public void LexMutlipartIdentifier()
		{
			TemplateLexer lexer = NewLexer("<$ test1 . test2 . test3   $>");

			Token t = NextTokenAssert(lexer, TokenType.Identifier, "test1.test2.test3");

			Assert.AreEqual(3, t.Parts.Length);
			Assert.AreEqual("test1", t.Parts[0]);
			Assert.AreEqual("test2", t.Parts[1]);
			Assert.AreEqual("test3", t.Parts[2]);

			NextTokenAssert(lexer, TokenType.EndTemplate, "}>");
			Assert.IsTrue(lexer.Eof);

			AssertNoErrors();
		}

		[Test]
		public void LexLiteralString()
		{
			TemplateLexer lexer = NewLexer("<$    \"test\"   $>");

			NextTokenAssert(lexer, TokenType.LiteralString, "test");

			NextTokenAssert(lexer, TokenType.EndTemplate, "}>");
			Assert.IsTrue(lexer.Eof);

			AssertNoErrors();

		}

		[Test]
		public void LexLiteralInt32()
		{
			TemplateLexer lexer = NewLexer("<$ 123 -456 $>");

			NextTokenAssert(lexer, TokenType.LiteralInt32, "123");
			NextTokenAssert(lexer, TokenType.LiteralInt32, "-456");

			NextTokenAssert(lexer, TokenType.EndTemplate, "}>");
			Assert.IsTrue(lexer.Eof);
			AssertNoErrors();
		}

		[Test]
		public void LexLiteralChar()
		{
			TemplateLexer lexer = NewLexer("<$ 'a' 'b' 'c' $>");

			NextTokenAssert(lexer, TokenType.LiteralChar, "a");
			NextTokenAssert(lexer, TokenType.LiteralChar, "b");
			NextTokenAssert(lexer, TokenType.LiteralChar, "c");

			NextTokenAssert(lexer, TokenType.EndTemplate, "}>");
			Assert.IsTrue(lexer.Eof);
			AssertNoErrors();
		}

		[Test]
		public void LexLiteralDouble()
		{
			TemplateLexer lexer = NewLexer("<$ 123.456 456.789 $>");

			NextTokenAssert(lexer, TokenType.LiteralDouble, "123.456");
			NextTokenAssert(lexer, TokenType.LiteralDouble, "456.789");

			NextTokenAssert(lexer, TokenType.EndTemplate, "}>");
			Assert.IsTrue(lexer.Eof);
			AssertNoErrors();
		}

		[Test]
		public void LexLiteralStringWithEscapeSequences()
		{
			//" \" \t \n " \
			TemplateLexer lexer = NewLexer("<$ \" \\\" \\t \\n \\\\\"	 $>");

			NextTokenAssert(lexer, TokenType.LiteralString, " \" \t \n \\");

			NextTokenAssert(lexer, TokenType.EndTemplate, "}>");
			Assert.IsTrue(lexer.Eof);

			AssertNoErrors();
		}

		[Test]
		public void LexSingleCharacterToken()
		{
			TemplateLexer lexer = NewLexer("<$ ( ) [ ] = { }$>");
			NextTokenAssert(lexer, TokenType.OpenParen);
			NextTokenAssert(lexer, TokenType.CloseParen);
			NextTokenAssert(lexer, TokenType.OpenBracket);
			NextTokenAssert(lexer, TokenType.CloseBracket);
			NextTokenAssert(lexer, TokenType.OperatorAssign);
			NextTokenAssert(lexer, TokenType.OpenBrace);
			NextTokenAssert(lexer, TokenType.CloseBrace);
		}

		[Test]
		public void LexKeywords()
		{
			TemplateLexer lexer = NewLexer("<$ if else endif foreach in between next lookup set global null $>");
			NextTokenAssert(lexer, TokenType.KeywordIf);
			NextTokenAssert(lexer, TokenType.KeywordElse);
			NextTokenAssert(lexer, TokenType.KeywordEndIf);
			NextTokenAssert(lexer, TokenType.KeywordForEach);
			NextTokenAssert(lexer, TokenType.KeywordIn);
			NextTokenAssert(lexer, TokenType.KeywordBetween);
			NextTokenAssert(lexer, TokenType.KeywordNext);
			NextTokenAssert(lexer, TokenType.KeywordLookup);
			NextTokenAssert(lexer, TokenType.KeywordSet);
			NextTokenAssert(lexer, TokenType.KeywordGlobal);
			NextTokenAssert(lexer, TokenType.KeywordNull);

			//Assert.IsTrue(lexer.Eof);
		}

		[Test]
		public void LexSimpleVerbatimAndStatement()
		{
			TemplateLexer lexer = NewLexer("verbatim<$test$>mitaberv");

			NextTokenAssert(lexer, TokenType.Verbatim, "verbatim");
			NextTokenAssert(lexer, TokenType.Identifier, "test");
			NextTokenAssert(lexer, TokenType.Verbatim, "mitaberv");

			NextTokenAssert(lexer, TokenType.EndTemplate, "}>");
			Assert.IsTrue(lexer.Eof);

			AssertNoErrors();
		}


		[Test]
		public void LexCommments()
		{
			                            ///0123456789012345678901234567890123456789012345678901234567890
			TemplateLexer lexer = NewLexer("verbatim<$  /* ignore me */ test/*ignoreme*/$>mitaberv");

			NextTokenAssert(lexer, TokenType.Verbatim, "verbatim");
			NextTokenAssert(lexer, TokenType.Identifier, "test");
			NextTokenAssert(lexer, TokenType.Verbatim, "mitaberv");

			NextTokenAssert(lexer, TokenType.EndTemplate, "}>");
			Assert.IsTrue(lexer.Eof);

			AssertNoErrors();
		}

			[Test]
		public void	LexAnonymousTemplate()
		{
			TemplateLexer lexer = NewLexer("verbatim<$ <{test}> $>mitaberv");

			NextTokenAssert(lexer, TokenType.Verbatim, "verbatim");
			NextTokenAssert(lexer, TokenType.BeginTemplate);
			NextTokenAssert(lexer, TokenType.Verbatim, "test");
			NextTokenAssert(lexer, TokenType.EndTemplate);
			NextTokenAssert(lexer, TokenType.Verbatim, "mitaberv");

			NextTokenAssert(lexer, TokenType.EndTemplate, "}>");
			Assert.IsTrue(lexer.Eof);

			AssertNoErrors();
		}
	}
}
